package com.sdy.auth.provider;

import com.sdy.auth.api.AuthApi;
import com.sdy.auth.api.model.AuthDto;
import com.sdy.auth.api.model.LayTreeItem;
import com.sdy.auth.api.model.MenuDto;
import com.sdy.auth.api.model.UserDto;
import com.sdy.auth.api.model.UserInfo;
import com.sdy.auth.biz.model.SysDept;
import com.sdy.auth.biz.model.SysResource;
import com.sdy.auth.biz.model.SysRole;
import com.sdy.auth.biz.model.SysRoleResource;
import com.sdy.auth.biz.model.SysUser;
import com.sdy.auth.biz.service.AuthService;
import com.sdy.auth.biz.service.SysDeptService;
import com.sdy.auth.biz.service.SysResourceService;
import com.sdy.auth.biz.service.SysRoleResourceService;
import com.sdy.auth.biz.service.SysUserService;
import com.sdy.common.model.Response;
import com.sdy.common.model.Result;
import com.sdy.common.utils.StringUtil;
import com.sdy.mvc.annotation.RemoteService;
import com.sdy.mvc.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@RemoteService
public class AuthProvider implements AuthApi {
    @Autowired
    private AuthService authService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysResourceService sysResourceService;
    @Autowired
    private SysDeptService sysDeptService;
    @Autowired
    private SysRoleResourceService sysRoleResourceService;

    /**
     * 根据路径查询资源
     */
    @Override
    public Response checkAuthorization(Integer userId,
                                       String path,
                                       String appCode) {
        return Response.success(authService.checkAuthorization(userId, path, appCode));
    }

    @Override
    public Response<MenuDto> menu(Integer userId, String appCode) {
        SysResource res = authService.findMenu(userId, appCode);
        return Response.success(JsonUtil.convert(res, MenuDto.class));
    }

    @Override
    public Response<UserDto> userInfo(Integer userId) {
        SysUser user = sysUserService.getById(userId);
        if (user == null) {
            return Response.success();
        }
        UserDto vo = new UserDto();
        vo.setId(user.getId())
                .setName(user.getName())
                .setMail(user.getMail())
                .setGender(user.getGender())
                .setImgUrl(user.getImgUrl())
                .setPhone(user.getPhone())
                .setProfile(user.getProfile())
                .setState(user.getState())
                .setType(user.getType())
                .setIdCard(user.getIdCard())
                .setLoginName(user.getLoginName());
        return Response.success(vo);
    }

    /**
     * 登录
     */
    @Override
    public Result<UserInfo> login(String username, 
                                  Integer deptId,
                                  String password,
                                  String token,
                                  String ip) {
        String realUserName = username;
        if (deptId != null) {
            List<SysDept> deptAccessorList = sysDeptService.getDeptAccessorList(deptId);
            for (SysDept item : deptAccessorList) {
                if (StringUtil.isNotBlank(item.getSuffix())) {
                    realUserName = realUserName.concat(".").concat(item.getSuffix());
                }
            }
        }
        Result<com.sdy.auth.biz.model.dto.UserInfo> r = authService.login(realUserName, password, token, ip);
        if (!r.getSuccess()) {
            return new Result<>(null, r.getMessage(), r.getCode(), r.getSuccess());
        }
        return new Result<>(new UserInfo()
                .setUserId(r.getData().getUserId())
                .setLoginName(r.getData().getLoginName())
                .setUserName(r.getData().getUserName()),
                r.getMessage(),
                r.getCode(),
                r.getSuccess());
    }

    /**
     * 获取下属用户集合
     */
    @Override
    public Response subuser(Integer userId) {
        Result<Collection> result = authService.getManagerUserList(userId);
        if (!result.getSuccess()) {
            return Response.error(result.getMessage(), result.getCode());
        }
        return Response.success(result.getData());
    }

    @Override
    public Response<Collection> deptManagerTree(Integer userId) {
//        authService.deptManagerTree(userId);
        return null;
    }

    /**
     * 第三方登录接口
     */
    @Override
    public Response loginS(String username,
                           String appid,
                           String key,
                           String timestamp,
                           String ip) {
        return Response.success(authService.login(username, appid, key, timestamp, ip));
    }

    @Override
    public Response findAuthTreeByRole(Integer roleId) {
        return Response.success(JsonUtil.convert(authService.findAuthTreeByRole(roleId), LayTreeItem.class));
    }

    @Override
    public String getDefaultAppUrl(String appCode) {
        if (StringUtil.isBlank(appCode)) {
            appCode = "user-center";
        }
        return sysResourceService.findAppByCode(appCode).getUrl();
    }

    @SuppressWarnings("unchecked")
    @Override
    public AuthDto getAuthTree(String appCode, Integer userId) {
        SysResource app = sysResourceService.findAppByCode(appCode);
        if (app == null) {
            return null;
        }
        boolean admin = false;
        List<Integer> adminRoleList = authService.findAdminRole();
        List<Integer> userRoleIdList = authService.findRoleByUser(userId, true)
                .stream()
                .map(SysRole::getId)
                .collect(Collectors.toList());
        adminRoleList.retainAll(userRoleIdList);
        if (!adminRoleList.isEmpty()) {
            admin = true;
        }
        // app所有权限
        List<SysResource> resourceList = sysResourceService.lambdaQuery()
                .eq(SysResource::getRootId, app.getId())
                .isNotNull(SysResource::getCode)
                .ne(SysResource::getCode, "")
                .eq(SysResource::getState, 1)
                .orderByAsc(SysResource::getId)
                .list();
        // 角色所有权限
        List<Integer> authedResIdSet = Collections.emptyList();
        if (!userRoleIdList.isEmpty()) {
            authedResIdSet = sysRoleResourceService.lambdaQuery()
                    .eq(SysRoleResource::getRootResourceId, app.getId())
                    .in(SysRoleResource::getRoleId, userRoleIdList)
                    .orderByAsc(SysRoleResource::getRootResourceId, SysRoleResource::getSort, SysRoleResource::getId)
                    .list().stream().map(SysRoleResource::getResourceId).distinct().collect(Collectors.toList());
        }
        Map<Integer, Integer> sortMap = new HashMap<>();
        for (SysResource res : resourceList) {
            sortMap.put(res.getId(), authedResIdSet.indexOf(res.getId()));
        }
        resourceList.sort((o1, o2) -> {
            int w = sortMap.get(o1.getId()) - sortMap.get(o2.getId());
            return w == 0 ? o1.getId() - o2.getId() : w;
        });
        app.setAuthed(isAuthed(
                admin,
                app.getAuthentication(),
                app.getAuthorization(),
                userId != null,
                authedResIdSet.contains(app.getId())) ? 1 : 0);
        for (SysResource sysResource : resourceList) {
            sysResource.setAuthed(isAuthed(
                    admin,
                    sysResource.getAuthentication(),
                    sysResource.getAuthorization(),
                    userId != null,
                    authedResIdSet.contains(sysResource.getId())) ? 1 : 0);
        }
        AuthDto root = formatAuthDTO(app);
        root.setChildren(new ArrayList<>());
        List<AuthDto> resList = resourceList.stream().map(this::formatAuthDTO).collect(Collectors.toList());
        
        Map<Integer, List<AuthDto>> pMap = new HashMap<>();
        resList.forEach(res -> {
            List<AuthDto> arr = pMap.computeIfAbsent(res.getParentId(), key -> new ArrayList<>());
            arr.add(res);
        });
        resList.forEach(res -> {
            res.setChildren(pMap.get(res.getId()));
            if (res.getParentId().equals(root.getId())) {
                root.getChildren().add(res);
            }
        });
        return root;
    }
    
    private boolean isAuthed(boolean admin, int authentication, int authorization, boolean logined, boolean authed) {
        if (admin) {
            return true;
        }
        if (authentication == 2) {
            return true;
        }
        if (!logined) {
            return false;
        }
        if (authorization == 2) {
            return true;
        }
        return authed;
    }
    
    private AuthDto formatAuthDTO(SysResource resource) {
        return new AuthDto()
                .setId(resource.getId())
                .setParentId(resource.getParentId())
                .setCode(resource.getCode())
                .setName(resource.getName())
                .setAuth(resource.getAuthed().equals(1))
                .setRoute(resource.getRoute())
                .setType(resource.getType());
    }
}
